/**
 * Copyright (c) 2006-2015, JGraph Ltd
 * Copyright (c) 2006-2015, Gaudenz Alder
 */
/**
 * Class: mxStylesheetCodec
 *
 * Codec for <mxStylesheet>s. This class is created and registered
 * dynamically at load time and used implicitely via <mxCodec>
 * and the <mxCodecRegistry>.
 */
var mxStylesheetCodec = mxCodecRegistry.register(function () {
  var codec = new mxObjectCodec(new mxStylesheet())

  /**
	 * Function: encode
	 *
	 * Encodes a stylesheet. See <decode> for a description of the
	 * format.
	 */
  codec.encode = function (enc, obj) {
    var node = enc.document.createElement(this.getName())

    for (var i in obj.styles) {
      var style = obj.styles[i]
      var styleNode = enc.document.createElement('add')

      if (i != null) {
        styleNode.setAttribute('as', i)

        for (var j in style) {
          var value = this.getStringValue(j, style[j])

          if (value != null) {
            var entry = enc.document.createElement('add')
            entry.setAttribute('value', value)
            entry.setAttribute('as', j)
            styleNode.appendChild(entry)
          }
        }

        if (styleNode.childNodes.length > 0) {
          node.appendChild(styleNode)
        }
      }
    }

	    return node
  }

  /**
	 * Function: getStringValue
	 *
	 * Returns the string for encoding the given value.
	 */
  codec.getStringValue = function (key, value) {
    var type = typeof (value)

    if (type == 'function') {
      value = mxStyleRegistry.getName(value)
    } else if (type == 'object') {
      value = null
    }

    return value
  }

  /**
	 * Function: decode
	 *
	 * Reads a sequence of the following child nodes
	 * and attributes:
	 *
	 * Child Nodes:
	 *
	 * add - Adds a new style.
	 *
	 * Attributes:
	 *
	 * as - Name of the style.
	 * extend - Name of the style to inherit from.
	 *
	 * Each node contains another sequence of add and remove nodes with the following
	 * attributes:
	 *
	 * as - Name of the style (see <mxConstants>).
	 * value - Value for the style.
	 *
	 * Instead of the value-attribute, one can put Javascript expressions into
	 * the node as follows if <mxStylesheetCodec.allowEval> is true:
	 * <add as="perimeter">mxPerimeter.RectanglePerimeter</add>
	 *
	 * A remove node will remove the entry with the name given in the as-attribute
	 * from the style.
	 *
	 * Example:
	 *
	 * (code)
	 * <mxStylesheet as="stylesheet">
	 *   <add as="text">
	 *     <add as="fontSize" value="12"/>
	 *   </add>
	 *   <add as="defaultVertex" extend="text">
	 *     <add as="shape" value="rectangle"/>
	 *   </add>
	 * </mxStylesheet>
	 * (end)
	 */
  codec.decode = function (dec, node, into) {
    var obj = into || new this.template.constructor()
    var id = node.getAttribute('id')

    if (id != null) {
      dec.objects[id] = obj
    }

    node = node.firstChild

    while (node != null) {
      if (!this.processInclude(dec, node, obj) && node.nodeName == 'add') {
        var as = node.getAttribute('as')

        if (as != null) {
          var extend = node.getAttribute('extend')
          var style = (extend != null) ? mxUtils.clone(obj.styles[extend]) : null

          if (style == null) {
            if (extend != null) {
              mxLog.warn('mxStylesheetCodec.decode: stylesheet ' +
								extend + ' not found to extend')
            }

            style = new Object()
          }

          var entry = node.firstChild

          while (entry != null) {
            if (entry.nodeType == mxConstants.NODETYPE_ELEMENT) {
						 	var key = entry.getAttribute('as')

						 	if (entry.nodeName == 'add') {
							 	var text = mxUtils.getTextContent(entry)
							 	var value = null

							 	if (text != null && text.length > 0 && mxStylesheetCodec.allowEval) {
							 		value = mxUtils.eval(text)
							 	} else {
							 		value = entry.getAttribute('value')

							 		if (mxUtils.isNumeric(value)) {
                    value = parseFloat(value)
                  }
							 	}

							 	if (value != null) {
							 		style[key] = value
							 	}
						 	} else if (entry.nodeName == 'remove') {
						 		delete style[key]
						 	}
            }

            entry = entry.nextSibling
          }

          obj.putCellStyle(as, style)
        }
      }

      node = node.nextSibling
    }

    return obj
  }

  // Returns the codec into the registry
  return codec
}())

/**
 * Variable: allowEval
 *
 * Static global switch that specifies if the use of eval is allowed for
 * evaluating text content. Default is true. Set this to false if stylesheets
 * may contain user input.
 */
mxStylesheetCodec.allowEval = true
